#include "AppStateManager.h"

AppStateManager::AppStateManager()
{
	m_bShutdown = false;
}


AppStateManager::~AppStateManager()
{
    while (!m_ActiveStateStack.empty())
	{
		m_ActiveStateStack.back()->Exit();
		m_ActiveStateStack.pop_back();
	}

	tStateInfo tempStateInfo;
	while (!m_States.empty())
	{
		tempStateInfo = m_States.back();
		if (tempStateInfo.pState)
			tempStateInfo.pState->Destroy();
        m_States.pop_back();
	}
}

void AppStateManager::ManageAppState(Ogre::String stateName, AppState* state)
{
	try
	{
		tStateInfo new_state_info;
		new_state_info.szName = stateName;
		new_state_info.pState = state;
		m_States.push_back(new_state_info);
	}
	catch(std::exception& e)
	{
		delete state;
		throw Ogre::Exception(Ogre::Exception::ERR_INTERNAL_ERROR, 
							"Error while trying to manage a new AppState\n", 
							 Ogre::String(e.what()) ,"void AppStateManager::ManageAppState", 
							__FILE__, __LINE__);
	}
}

AppState* AppStateManager::FindByName(Ogre::String stateName)
{
	std::vector<tStateInfo>::iterator itr;

	for (itr = m_States.begin(); itr != m_States.end(); itr++)
	{
		if (itr->szName == stateName)
			return itr->pState;
	}

	return NULL;
}

void AppStateManager::Start(AppState* state)
{
	ChangeAppState(state);

	int nDeltaTime = 1;
	int startTime = 0;

	while (!m_bShutdown)
	{
		if (AppFramework::getSingletonPtr()->m_pRenderWnd->isClosed())
			m_bShutdown = true;

		Ogre::WindowEventUtilities::messagePump();

		if (AppFramework::getSingletonPtr()->m_pRenderWnd->isActive())
		{
			startTime = AppFramework::getSingletonPtr()->m_pTimer->getMillisecondsCPU();

			AppFramework::getSingletonPtr()->m_inputContext.mKeyboard->capture();
			AppFramework::getSingletonPtr()->m_inputContext.mMouse->capture();

			m_ActiveStateStack.back()->Update(nDeltaTime);

			AppFramework::getSingletonPtr()->UpdateFmk(nDeltaTime);
			AppFramework::getSingletonPtr()->m_pRoot->renderOneFrame();

			nDeltaTime = AppFramework::getSingletonPtr()->m_pTimer->getMillisecondsCPU() - startTime;
		}
		else
		{
		#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            Sleep(1000);
		#else
            sleep(1);
		#endif
		}
	}

	AppFramework::getSingletonPtr()->m_pLog->logMessage("Main loop quit");
}

void AppStateManager::ChangeAppState(AppState* state)
{
	if (!m_ActiveStateStack.empty())
	{
		m_ActiveStateStack.back()->Exit();
		m_ActiveStateStack.pop_back();
	}

	m_ActiveStateStack.push_back(state);
	Init(state);
	m_ActiveStateStack.back()->Enter();
}

bool AppStateManager::PushAppState(AppState* state)
{
	if(!m_ActiveStateStack.empty())
	{
		if (!m_ActiveStateStack.back()->Pause())
			return false;
	}

	m_ActiveStateStack.push_back(state);
	Init(state);
	m_ActiveStateStack.back()->Enter();

	return true;
}

void AppStateManager::PopAppState()
{
	if (!m_ActiveStateStack.empty())
	{
		m_ActiveStateStack.back()->Exit();
		m_ActiveStateStack.pop_back();
	}

	if (!m_ActiveStateStack.empty())
	{
		Init (m_ActiveStateStack.back());
		m_ActiveStateStack.back()->Resume();
	}
	else
	{
		Shutdown();
	}
}

void AppStateManager::PopAllAndPushAppState(AppState* state)
{
    while(!m_ActiveStateStack.empty())
    {
        m_ActiveStateStack.back()->Exit();
        m_ActiveStateStack.pop_back();
    }

	PushAppState(state);
}

void AppStateManager::PauseAppState()
{
	if (!m_ActiveStateStack.empty())
	{
		m_ActiveStateStack.back()->Pause();
	}

	if (m_ActiveStateStack.size() > 2)
	{
		Init(m_ActiveStateStack.at(m_ActiveStateStack.size() - 2));
		m_ActiveStateStack.at(m_ActiveStateStack.size() - 2)->Resume();
	}
}

void AppStateManager::Shutdown()
{
	m_bShutdown = true;
}

void AppStateManager::Init(AppState* state)
{
	AppFramework::getSingletonPtr()->m_inputContext.mKeyboard->setEventCallback(state);
	AppFramework::getSingletonPtr()->m_inputContext.mMouse->setEventCallback(state);
	AppFramework::getSingletonPtr()->m_pTrayMgr->setListener(state);

	AppFramework::getSingletonPtr()->m_pRenderWnd->resetStatistics();
}
